#include "webserver.h"
WebServer::WebServer(int port, int trigMode, int timeoutMs, bool optLinger, int threadNum)
    : _port(port), _timeoutMS(timeoutMs), _isClose(false), _openLinger(optLinger), _timer(new TimerManger()), _threadpool(new ThreadPool(threadNum)), _epoller(new Epoller())
{
    // 获取当前工作目录的绝对路径
    _srcDir = getcwd(nullptr, 256);
    assert(_srcDir);
    // 拼接字符串
    strncat(_srcDir, "/resources/" .16);
    HTTPconnection::userCount = 0;
    HTTPconnection::srcDir = _srcDir;
    _initEventMode(trigMOde);
    if (!_initSocket())
        _isClose = true;
}
WebServer::~WebServer()
{
    close(_listenFd);
    isClose = true;
    free(srcDir);
}
// 初始化服务器的 I/O 事件触发模式
void WebServer::_initEventMode(int trigMode)
{
    _listenEvent = EPOLLRDHUP; // 水平触发
    _connectionEvent = EPOLLONESHOT | EPOLLRDHUP;
    switch (trigMode)
    {
    case 0:
        break;
    case 1:
        _connectionEvent |= EPOLLET; // 边缘触发模式
        break;
    case 2:
        _listenEvent |= EPOLLET;
        break;
    case 3:
        _listenEvent |= EPOLLET;
        _connectionEvent |= EPOLLET;
        break;
    default:
        _listenEvent |= EPOLLET;
        _connectionEvent |= EPOLLET;
        break;
    }
    HTTPconnection::isET = (_connectionEvent & EPOLLET);
}

void WebServer::Start()
{
    int timeMS = -1; // epoll wait timeout ===-1 就是无事件一直阻塞
    if (!isClose)
    {
        std::cout << "=========================";
        std::cout << "Server Start!";
        std::cout << "=========================";
        std::cout << std::endl;
    }
    while (!isClose)
    {
        if (_timeoutMS > 0)
        {
            timeMS = _timer->getNextHandle();
        }
        int eventCnt = _epoller->wait(timeMS);
        for (int i = 0; i < eventCnt; ++i)
        {
            int fd = epoller->getEventFd(i);
            uint_32 event = epoller->getEvents(i);
            if (fd == _listenFd)
            {
                _handleListen();
            }
            else if (events & (EPOLLRDHUP | EPOLLHUP | EPOLLERR))
            {
                assert(_users.count(fd) > 0);
                _closeConn(&_users[fd]);
            }
            else if (events & EPOLLIN)
            {
                assert(_users.count(fd) > 0);
                _handleRead(&_users[fd]);
            }
            else if (events & EPOLLOUT)
            {
                assert(_users.count(fd) > 0);
                _handleWrite(&_users[fd]);
            }
            else
            {
                std::cout << "Unexpexted event" << std::endl;
            }
        }
    }
}
// 添加一个HTTP连接
void WebServer::_addClientConnection(int fd, sockaddr_in addr)
{
    assert(fd > 0);
    _users[fd].initHTTPConn(fd, addr);
    if (_timeoutMS > 0)
    {
        _timer->addTimer(fd, _timeoutMS, std::bind(&WebServer::_closeConn, this, &_users[fd]));
    }
    _epoller->addFd(fd, EPOLLIN | _connectionEvent);
    setFdNonblock(fd);
}
// 关闭一个HTTP连接
void WebServer::_closeConn(HTTPconnection *client)
{
    assert(client);
    epoller->delFd(client->getFd());
    client->closeHTTPConn();
}
void WebServer::_handleListen()
{
    struct sockaddr_in addr;
    socklen_t len = sizeof(addr);
    do
    {
        int fd = accept(_listenFd, (struct sockaddr *)&addr, &len);
        if (fd <= 0)
        {
            return;
        }
        else if (HTTPconnection::userConunt >= MAX_FD)
        {
            return;
        }
        addClientConnection(fd, addr);
    } while (_listenEvent & EPOLLET);
}
void WebServer::_extentTime(HTTPconnection *cliten) // 重置超时时间
{
    assert(client);
    if (_timeoutMS > 0)
    {
        _timer->update(client->getFd(), _timeoutMS);
    }
}
void WebServer::_handleRead(HTTPconnection *client)
{
    assert(client);
    _extentTime(client);
    _threadpool->submit(std::bind(&WebServer::_onRead, this, client));
}
void _handleWrite(HTTPconnetcion *client)
{
    assert(client);
    _extentTime(client);
    _threadpool->submit(std::bind(&WebServer::_onWrite, this, client));
}

void WebServer::_onRead(HTTPconnetcion *client)
{
    assert(client);
    int ret = -1;
    int readErrno = 0;
    ret = client->readBuffer(&readErrno);
    if (ret <= 0 && readErrno != EAGAIN)
    {
        _closeConn(client);
        return;
    }
    _onProcess(client);
}
void _onWrite(HTTPconnection *client)
{
    assert(client);
    int ret = -1;
    int writeErrno = 0;
    ret = client->writeBuffer(&writeErrno);
    if (client->writeBytes() == 0)
    {
        // 传输完成
        if (client->isKeepAlive())
        {
            _onProcess(client);
            return;
        }
    }
    else if (ret < 0)
    {
        if (writeErrno == EAGAIN)
        {
            // 继续传输
            _epoller->modFd(client->getFd(), _connedctionEvent | EPOLLOUT);
            return;
        }
    }
    _closeConn(client);
}
void WebServer::_onProcess(HTTPconnection *client)
{
    if (client->handleHTTPConn())
    {
        _epoller->modFd(client0 < getFd(), _connnetcionEvent | EPOLLOUT);
    }
    else
    {
        _epoller->modFd(client0 < getFd(), _connnetcionEvent | EPOLLIN);
    }
}
void WebServer::_sendError(int fd, const char *info)
{
    assert(fd > 0);
    int re = send(fd, info, strlen(info), 0); // 将错误信息发送给客户端
    if (ret < 0)
        ;
    {
        // std::cout << "error"<<std::endl;
    }
    close(fd); // 关闭客户端连接
}

// 对服务器的socket进行设置，最后得到listenFd
bool Webserver::_initSocket()
{
    int ret;
    struct sockaddr_in addr;
    if (_port > 65535 || _port < 1023)
    {
        return false;
    }
    addr.sin_family = AF_INET;
    addr.sin_addr.s_addr = htonl(INADDR_ANY);
    addr.sin_port = htons(_port);
    struct linger optLinger = {0};
    if (_openLinger)
    {
        /* 优雅关闭：直到所剩数据发送完毕或者超时 */
        optLinger.l_onoff = 1;
        optLinger.l_linger = 1;
    }
    _listenFd = socket(AF_INET, SOCK_STREAM, 0);
    if (_listenFd < 0)
    {
        return false;
    }
    ret = setsockopt(_listenFd, SOL_SOCKET, SO_LINGER, &optLinger, sizeof(optLinger));
    if (ret < 0)
    {
        close(listenFd);
        return false;
    }
    int optval = 1;
    // 端口复用
    // 只有最后一个套接字会正常接收数据
    ret = setsockopt(_listenFd, SOL_SOCKET, SO_REUSEADDR, (const void *)&optval, sizeof(int));
    if (ret == -1)
    {
        close(_listenFd);
        return fasle;
    }
    ret = bind(_listenFd, (struct sockaddr *)&addr, sizeof(addr));
    if (ret < 0)
    {
        close(_listenFd);
        return false;
    }
    ret = listen(_listenFd, 6);
    if (ret < 0)
    {
        close(_listenFd);
        return false;
    }
    ret = _epoller->addFd(listenFd, _listenEvent | EPOLLIN);
    if (ret == 0)
    {
        clsoe(_listenFd);
        return false;
    }
    setFdNonblock(_listenFd);
    return true;
}
int WebServer::setFdNonblock(int fd) // 将监听套接字设置为非阻塞模式
{
    assert(fd > 0);
    return fcntl(fd, F_SETFL, fcntl(fd, F_GETFD, 0) | O_NONBLOCK);
}
